﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace THO7AlgoritmTimerApplication
{
        class Median3x3Bogo : VisionAlgorithm
        {
            public Median3x3Bogo(String name) : base(name) { }

            private static Random rnd;
            public override System.Drawing.Bitmap DoAlgorithm(System.Drawing.Bitmap sourceImage)
            {

                Rectangle rect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
                Bitmap returnImage = (Bitmap)sourceImage.Clone();

                BitmapData srcData = sourceImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                BitmapData desData = returnImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);






                int stride = srcData.Stride;
                int nOffset = stride - sourceImage.Width * 3;
                System.IntPtr Scan0 = srcData.Scan0;
                System.IntPtr DesScan0 = desData.Scan0;

                unsafe
                {
                    byte* p = (byte*)(void*)Scan0;
                    byte* DesP = (byte*)(void*)DesScan0;

                    p += stride;
                    DesP += stride;
                    for (int y = 1; y < sourceImage.Height - 1; ++y)
                    {
                        p += 3;

                        DesP += 3;
                        for (int x = 1; x < sourceImage.Width - 1; ++x)
                        {
                            byte[][] pixelList = getList(p, 3, stride, nOffset);


                            pixelList[0] = bogosort(pixelList[0]);
                            pixelList[1] = bogosort(pixelList[1]);
                            pixelList[2] = bogosort(pixelList[2]);

                            DesP[0] = pixelList[0][4];
                            DesP[1] = pixelList[1][4];
                            DesP[2] = pixelList[2][4];


                            p += 3;
                            DesP += 3;


                        }


                        p += nOffset;
                        DesP += nOffset;

                    }
                }
                returnImage.UnlockBits(desData);
                sourceImage.UnlockBits(srcData);
                return returnImage;
            }

            private unsafe byte[][] getList(byte* p, int size, int stride, int nOffset)
            {


                byte[][] pixelList = new byte[3][];
                pixelList[0] = new byte[size * size];
                pixelList[1] = new byte[size * size];
                pixelList[2] = new byte[size * size];
                int tempSize = ((size) - 1) / 2;
                p -= tempSize * 3;
                p -= tempSize * stride;
                int count = 0;

                for (int y = -tempSize; y <= tempSize; ++y)
                {
                    for (int x = -tempSize; x <= tempSize; ++x)
                    {
                        pixelList[0][count] = p[0];
                        pixelList[1][count] = p[1];
                        pixelList[2][count] = p[2];
                        p += 3;
                        count++;

                    }

                    p += nOffset;

                }
                p -= tempSize * 3;
                p -= tempSize * stride;


                return pixelList;
            }

        public static byte[] bogosort(byte[] items)
        {
        while(!inOrder(items))
            shuffle(items);
        return items;
        }


        static void shuffle(byte[] items)
        {
            if (rnd == null) rnd = new Random();
            for (int i = 0; i < items.Length; i++)
                Swap(items, i, rnd.Next(0, items.Length - 1));
        }
        
        private static void Swap(byte[] items, int item1, int item2)
        {
            byte temp = items[item1];
            items[item1] = items[item2];
            items[item2] = temp;
        }


        static bool inOrder(byte[] items)
        {
            for(int i = 0; i < items.Length -1; i++)
            {
                 if(items[i] > items[i+1])
                      return false;
            }
            return true; 
        }

    }
}

